#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include "ringBuffer.h"

// ringbuffer 私有结构
typedef struct _ring_buffer_body_t
{
	uint8_t *pRead;   // 当前读取指针
	uint8_t *pWrite;  // 当前写入指针
	uint8_t *pHead;   // 内存头
	uint8_t *pTail;   // 内存尾
	int size;         // 总内存大小
	int remainSize;   // 剩余内存大小
} RING_BUFFER_BODY_t;

// 获取私有结构
static RING_BUFFER_BODY_t *get_body(RING_BUFFER_t *ring)
{
	if (ring == NULL)
		return NULL;
	return (RING_BUFFER_BODY_t *)ring->body;
}

// 写入指定长度数据
static int ring_buffer_write(RING_BUFFER_t *ring, uint8_t *data, int len)
{
	RING_BUFFER_BODY_t *ringBufferBody = get_body(ring);
	if (NULL == ringBufferBody || NULL == data)
		return 0;
    
    // 如果写入字节数大于可写入字节数，则丢弃
	if (len > ringBufferBody->remainSize)
		return 0;

	if (ringBufferBody->pWrite + len > ringBufferBody->pTail)
	{
        // 写入长度会达到内存尾部，分两段写入，先写入到尾部，再从头开始写
		memcpy(ringBufferBody->pWrite, data, (ringBufferBody->pTail - ringBufferBody->pWrite));
		memcpy(ringBufferBody->pHead, data + (ringBufferBody->pTail - ringBufferBody->pWrite), len - (ringBufferBody->pTail - ringBufferBody->pWrite));
		ringBufferBody->pWrite = ringBufferBody->pHead + len - (ringBufferBody->pTail - ringBufferBody->pWrite);
	}
	else
	{
        // 直接写入
		memcpy(ringBufferBody->pWrite, data, len);
		ringBufferBody->pWrite += len;
	}

	ringBufferBody->remainSize -= len;
	return len;
}

// 写入一个字节
static int ring_buffer_write_byte(RING_BUFFER_t *ring, uint8_t data)
{
	RING_BUFFER_BODY_t *ringBufferBody = get_body(ring);
	if (NULL == ringBufferBody)
		return 0;

	if (ringBufferBody->remainSize < 1)
		return 0;
    // 写到尾部从头开始
	if(ringBufferBody->pTail - ringBufferBody->pWrite == 0)
		ringBufferBody->pWrite = ringBufferBody->pHead;
	
	memcpy(ringBufferBody->pWrite, &data, 1);

	ringBufferBody->pWrite ++;

	ringBufferBody->remainSize -= 1;
	
	return 1;
}

// 读取指定长度的数据
static int ring_buffer_read(RING_BUFFER_t *ring, uint8_t *data, int len)
{
	RING_BUFFER_BODY_t *ringBufferBody = get_body(ring);

	if (NULL == ringBufferBody || NULL == data)
		return -1;
    
    // 当前ringbuffer保存的数据总长度
	int avaliable_size = ringBufferBody->size - ringBufferBody->remainSize;

	if (len > avaliable_size)
		len = avaliable_size;

	if (ringBufferBody->pRead + len > ringBufferBody->pTail)
	{
        // 读取长度会达到内存尾部，分两段读取，先读取到尾部，再从头开始读
		memcpy(data, ringBufferBody->pRead, ringBufferBody->pTail - ringBufferBody->pRead);
		memcpy(data + (ringBufferBody->pTail - ringBufferBody->pRead), ringBufferBody->pHead, len - (ringBufferBody->pTail - ringBufferBody->pRead));
		ringBufferBody->pRead = ringBufferBody->pHead + len - (ringBufferBody->pTail - ringBufferBody->pRead);
	}
	else
	{
        // 直接读取
		memcpy(data, ringBufferBody->pRead, len);
		ringBufferBody->pRead += len;
	}

	ringBufferBody->remainSize += len;
	return len;
}

// 将指定长度的数据恢复到ringbuffer中
static int ring_buffer_restore(RING_BUFFER_t *ring, uint8_t *data, int len)
{
	RING_BUFFER_BODY_t *ringBufferBody = get_body(ring);

	if (NULL == ringBufferBody || NULL == data || len <= 0)
		return -1;

	int avaliable_size = ringBufferBody->size - ringBufferBody->remainSize;

	if (len > avaliable_size)
		return -1;

	if (ringBufferBody->pRead - len < ringBufferBody->pHead)
	{   // 待恢复的数据会到达内存头部，先恢复头部到读取指针的数据，再恢复尾部到写入指针的数据
        // 因为前面判断过可用大小是大于要恢复的大小，这里如果会达到内存头部，则读指针一定是比写指针小的，不用考虑读指针大于写指针的情况
		memcpy(ringBufferBody->pHead, data + len - (ringBufferBody->pRead - ringBufferBody->pHead), ringBufferBody->pRead - ringBufferBody->pHead);
		memcpy(ringBufferBody->pTail - (len - (ringBufferBody->pRead - ringBufferBody->pHead) ), data, len - (ringBufferBody->pRead - ringBufferBody->pHead));
		ringBufferBody->pRead = ringBufferBody->pTail - (len - (ringBufferBody->pRead - ringBufferBody->pHead) );
	}
	else
	{
        // 直接恢复
		memcpy(ringBufferBody->pRead - len, data, len);
		ringBufferBody->pRead -= len;
	}

	ringBufferBody->remainSize -= len;
	return len;
}

// 清除ringbuffer保存的数据
static void ring_buffer_clear(RING_BUFFER_t *ring)
{
	RING_BUFFER_BODY_t *ringBufferBody = get_body(ring);
	if (NULL == ringBufferBody)
		return;

	memset(ringBufferBody, 0, ringBufferBody->size);
	ringBufferBody->pRead = ringBufferBody->pHead;
	ringBufferBody->pWrite = ringBufferBody->pHead;
	ringBufferBody->remainSize = ringBufferBody->size;
}

// 销毁ringbuffer数据结构
static void ring_buffer_destory(RING_BUFFER_t **ring)
{
	if (ring == NULL || *ring == NULL)
		return;

	RING_BUFFER_BODY_t *ringBufferBody = get_body(*ring);
	if (NULL == ringBufferBody)
	{
		free(*ring);
		return;
	}

	free(ringBufferBody->pHead);
	ringBufferBody->pHead = NULL;
	ringBufferBody->pRead = NULL;
	ringBufferBody->pWrite = NULL;
	ringBufferBody->pRead = NULL;

	free((*ring)->body);
	(*ring)->body = NULL;

	free(*ring);
	*ring = NULL;
}

// ringbuffer初始化
static int ring_buffer_init(RING_BUFFER_t *ring, int size)
{
	ring->write = ring_buffer_write;
	ring->write_byte = ring_buffer_write_byte;
	ring->read = ring_buffer_read;
    ring->restore = ring_buffer_restore;
	ring->clear = ring_buffer_clear;
	ring->destory = ring_buffer_destory;

	RING_BUFFER_BODY_t *ringBufferBody = get_body(ring);
	if (NULL == ringBufferBody)
		return -1;

	ringBufferBody->pHead = (uint8_t *)malloc(size);
	if (NULL == ringBufferBody->pHead)
		return -1;
	memset(ringBufferBody->pHead, 0, size);

	ringBufferBody->pTail = ringBufferBody->pHead + size;
	ringBufferBody->pRead = ringBufferBody->pHead;
	ringBufferBody->pWrite = ringBufferBody->pHead;
	ringBufferBody->size = size;
	ringBufferBody->remainSize = size;
	return 0;
}

// 创建ringbuffer数据结构
RING_BUFFER_t *create_ring_buffer(int size)
{
	RING_BUFFER_t *ring = (RING_BUFFER_t *)malloc(sizeof(RING_BUFFER_t));
	if (NULL == ring)
		return NULL;

	memset(ring, 0, sizeof(RING_BUFFER_t));

	ring->body = malloc(sizeof(RING_BUFFER_BODY_t));
	if (NULL == ring->body)
	{
		free(ring);
		return NULL;
	}

	ring_buffer_init(ring, size);

	return ring;
}